import Rect from './rect';
import { Direction, directionArr } from './type';
import SpacingMarker from '.';
import { toFixed } from './utils';

export function placeMark(
  rect1: Rect,
  rect2: Rect,
  direction: Direction,
  value: number,
  outside: boolean = false,
): void {
  // 中轴线位置
  const rect1MidX = rect1.top + rect1.height / 2;
  const rect1MidY = rect1.left + rect1.width / 2;
  const rect2MidX = rect2.top + rect2.height / 2;
  const rect2MidY = rect2.left + rect2.width / 2;
  // 水平方向无碰撞
  const horizontalNoColliding = rect1.top > rect2.bottom || rect1.bottom < rect2.top;
  // 垂直方向无碰撞
  const verticalNoColliding = rect1.left > rect2.right || rect1.right < rect2.left;
  // 水平方向有碰撞
  const horizontalColliding = !horizontalNoColliding;
  // 垂直方向有碰撞
  const verticalColliding = !verticalNoColliding;
  // 缩放
  const { scale } = SpacingMarker;
  // 方向反转
  let reverse: boolean = false;

  if (direction === 'top') {
    let width: number = scale;
    let height: number = value;
    let top: number = Math.min(rect1.top, rect2.top);
    let left: number = (Math.min(rect1.right, rect2.right) + Math.max(rect1.left, rect2.left)) / 2;

    if (outside) {
      if (rect1.top >= rect2.bottom) return;
      reverse = true;
      const sublineLeft = rect2MidY < rect1.left;
      const sublineRight = rect2MidY > rect1.right;
      // 上侧 rect1比rect2较下
      if (rect1.top >= rect2.top) {
        top = rect2.top;
        left = rect1MidY;
        const sublineWidth = Math.abs(left - rect2.left);
        if (verticalNoColliding) {
          // 左辅助线
          sublineLeft && createSubline(sublineWidth, scale, top, left - sublineWidth, direction);
          // 右辅助线
          sublineRight && createSubline(sublineWidth, scale, top, left, direction);
        }
      } else {
        top = rect1.bottom > rect2.top ? rect1.top : rect1.bottom;
        left = rect2MidY;
        const sublineWidth = Math.abs(left - rect1.left);
        if (verticalNoColliding) {
          // 左辅助线
          sublineLeft &&
            createSubline(sublineWidth, scale, top, rect1.left - sublineWidth, direction, horizontalNoColliding);
          // 右辅助线
          sublineRight && createSubline(sublineWidth, scale, top, rect1.left, direction, horizontalNoColliding);
        }
      }
      if (verticalColliding) left = (Math.min(rect1.right, rect2.right) + Math.max(rect1.left, rect2.left)) / 2;
    }

    if (toFixed(value) > 0) {
      createLine(width, height, top, left, `${reverse ? 'b' : 't'} · ${toFixed(value)}px`, direction);
    }
  } else if (direction === 'bottom') {
    let width: number = scale;
    let height: number = value;
    let top: number = Math.min(rect1.bottom, rect2.bottom);
    let left: number = (Math.min(rect1.right, rect2.right) + Math.max(rect1.left, rect2.left)) / 2;

    if (outside) {
      if (rect1.bottom <= rect2.top) return;
      reverse = true;
      const sublineLeft = rect2MidY < rect1.left;
      const sublineRight = rect2MidY > rect1.right;
      // 下侧 rect1比rect2较上
      if (rect1.bottom <= rect2.bottom) {
        top = rect1.bottom;
        left = rect1MidY;
        const sublineWidth = Math.abs(left - rect2.left);
        if (verticalNoColliding) {
          // 左辅助线
          sublineLeft && createSubline(sublineWidth, scale, top + value, left - sublineWidth, direction, true);
          // 右辅助线
          sublineRight && createSubline(sublineWidth, scale, top + value, left, direction, true);
        }
      } else {
        top = rect2.bottom;
        left = rect2MidY;
        const sublineWidth = Math.abs(left - rect1.left);
        if (verticalNoColliding) {
          // 左辅助线
          sublineLeft &&
            createSubline(sublineWidth, scale, top + value, rect1.left - sublineWidth, direction, horizontalColliding);
          // 右辅助线
          sublineRight && createSubline(sublineWidth, scale, top + value, rect1.left, direction, horizontalColliding);
        }
      }
      if (verticalColliding) left = (Math.min(rect1.right, rect2.right) + Math.max(rect1.left, rect2.left)) / 2;
    }

    if (toFixed(value) > 0) {
      createLine(width, height, top, left, `${reverse ? 't' : 'b'} · ${toFixed(value)}px`, direction);
    }
  } else if (direction === 'left') {
    let width: number = value;
    let height: number = scale;
    let top: number = (Math.min(rect1.bottom, rect2.bottom) + Math.max(rect1.top, rect2.top)) / 2;
    let left: number = Math.min(rect1.left, rect2.left);

    if (outside) {
      if (rect1.left >= rect2.right) return;
      const sublineTop = rect2MidX < rect1.top;
      const sublineBottom = rect2MidX > rect1.bottom;
      // 左侧 rect1比rect2较右
      if (rect1.left >= rect2.left) {
        top = rect1MidX;
        left = rect2.left;
        const sublineHeight = Math.abs(top - rect2.top);
        if (horizontalNoColliding) {
          // 上辅助线
          sublineTop && createSubline(scale, sublineHeight, top - sublineHeight, left, direction);
          // 下辅助线
          sublineBottom && createSubline(scale, sublineHeight, top, left, direction);
        }
      } else {
        reverse = true;
        top = rect2MidX;
        left = rect1.right > rect2.left ? rect1.left : rect1.right;
        const sublineHeight = Math.abs(top - rect1.top);
        if (horizontalNoColliding) {
          // 上辅助线
          sublineTop &&
            createSubline(scale, sublineHeight, rect1.top - sublineHeight, left, direction, verticalNoColliding);
          // 下辅助线
          sublineBottom && createSubline(scale, sublineHeight, rect1.top, left, direction, verticalNoColliding);
        }
      }
      if (horizontalColliding) top = (Math.min(rect1.bottom, rect2.bottom) + Math.max(rect1.top, rect2.top)) / 2;
    }

    if (toFixed(value) > 0) {
      createLine(width, height, top, left, `${reverse ? 'r' : 'l'} · ${toFixed(value)}px`, direction);
    }
  } else {
    let width: number = value;
    let height: number = scale;
    let top: number = (Math.min(rect1.bottom, rect2.bottom) + Math.max(rect1.top, rect2.top)) / 2;
    let left: number = Math.min(rect1.right, rect2.right);

    if (outside) {
      if (rect1.right <= rect2.left) return;
      const sublineTop = rect2MidX < rect1.top;
      const sublineBottom = rect2MidX > rect1.bottom;
      // 右侧 rect1比rect2较左
      if (rect1.right <= rect2.right) {
        top = rect1MidX;
        left = rect1.right;
        const sublineHeight = Math.abs(top - rect2.top);
        if (horizontalNoColliding) {
          // 上辅助线
          sublineTop && createSubline(scale, sublineHeight, top - sublineHeight, left + value, direction, true);
          // 下辅助线
          sublineBottom && createSubline(scale, sublineHeight, top, left + value, direction, true);
        }
      } else {
        reverse = true;
        top = rect2MidX;
        left = rect2.right;
        const sublineHeight = Math.abs(top - rect1.top);
        if (horizontalNoColliding) {
          // 上辅助线
          sublineTop &&
            createSubline(scale, sublineHeight, rect1.top - sublineHeight, left + value, direction, verticalColliding);
          // 下辅助线
          sublineBottom && createSubline(scale, sublineHeight, rect1.top, left + value, direction, verticalColliding);
        }
      }
      if (horizontalColliding) top = (Math.min(rect1.bottom, rect2.bottom) + Math.max(rect1.top, rect2.top)) / 2;
    }
    if (toFixed(value) > 0) {
      createLine(width, height, top, left, `${reverse ? 'l' : 'r'} · ${toFixed(value)}px`, direction);
    }
  }
}

function createLine(
  width: number,
  height: number,
  top: number,
  left: number,
  text: string,
  direction: Direction,
): void {
  const { scale } = SpacingMarker;
  const line: HTMLElement | null = SpacingMarker.appendToEl.querySelector(`.spacing-js-line-${direction}`);
  if (!line) return;
  line.style.width = `${width}px`;
  line.style.height = `${height}px`;
  line.style.top = `${top}px`;
  line.style.left = `${left}px`;
  line.style.display = 'block';

  const value: HTMLElement | null = SpacingMarker.appendToEl.querySelector(`.spacing-js-value-${direction}`);
  if (!value) return;
  value.innerText = text;
  value.style.display = 'inline-block';

  // 垂直标线
  if (['top', 'bottom'].includes(direction)) {
    let topOffset = top + height / 2;
    value.style.transform = `translateY(-50%) scale(${scale})`;
    value.style.transformOrigin = 'left center';
    value.style.top = `${topOffset}px`;

    let leftOffset = 4;
    if (scale > 1) {
      if (height < 10) leftOffset = 6;
      leftOffset *= scale;
    }
    value.style.left = `${left + leftOffset}px`;
  }
  // 水平标线
  else if (['left', 'right'].includes(direction)) {
    let leftOffset = left + width / 2;
    value.style.transform = `translateX(-50%) scale(${scale})`;
    value.style.transformOrigin = 'center top';
    value.style.left = `${leftOffset}px`;

    let topOffset = 4;
    if (scale > 1) {
      if (width < 30) topOffset = 6;
      if (width < 20) topOffset = 8;
      if (width < 10) topOffset = 10;
      topOffset *= scale;
    }
    value.style.top = `${top + topOffset}px`;
  }
}

function createSubline(
  width: number,
  height: number,
  top: number,
  left: number,
  direction: Direction,
  isOffset = false,
): void {
  let { scale, selectedColor } = SpacingMarker;
  const subline: HTMLElement | null = SpacingMarker.appendToEl.querySelector(`.spacing-js-subline-${direction}`);
  if (!subline) return;
  scale = scale <= 0.5 ? 0.5 : scale;
  subline.style.width = `${width}px`;
  subline.style.height = `${height}px`;
  subline.style.top = `${top}px`;
  subline.style.left = `${left}px`;
  // 垂直辅助线
  if (['left', 'right'].includes(direction)) {
    scale <= 0.5 && (subline.style.width = `${scale + 0.1}px`);
    subline.style.height = `${height + scale}px`;
    subline.style.left = `${left + (isOffset ? -1 : 0)}px`;
    subline.style.backgroundImage = `linear-gradient(to bottom, ${selectedColor} 0%, ${selectedColor} 50%, transparent 50%)`;
    subline.style.backgroundSize = `${1 * scale}px ${4 * scale}px`;
    subline.style.backgroundRepeat = `repeat-y`;
  }
  // 水平辅助线
  if (['top', 'bottom'].includes(direction)) {
    scale <= 0.5 && (subline.style.height = `${scale + 0.1}px`);
    subline.style.width = `${width + scale}px`;
    subline.style.top = `${top + (isOffset ? -1 : 0)}px`;
    subline.style.backgroundImage = `linear-gradient(to right, ${selectedColor} 0%, ${selectedColor} 50%, transparent 50%)`;
    subline.style.backgroundSize = `${4 * scale}px ${1 * scale}px`;
    subline.style.backgroundRepeat = `repeat-x`;
  }
  subline.style.display = 'block';
}

export function initMarks(): void {
  const { targetColor, zIndex } = SpacingMarker;
  // 标线
  directionArr.forEach((item: any) => {
    if (SpacingMarker.appendToEl.querySelector(`.spacing-js-line-${item}`)) return;
    const line = document.createElement('span');
    line.className = `spacing-js-line-${item}`;
    line.style.position = 'absolute';
    line.style.zIndex = `${zIndex - 2}`;
    line.style.backgroundColor = targetColor;
    line.style.boxSizing = 'border-box';
    line.style.pointerEvents = 'none';
    line.style.display = 'none';
    SpacingMarker.appendToEl.appendChild(line);
  });
  // 数值
  directionArr.forEach((item: any) => {
    if (SpacingMarker.appendToEl.querySelector(`.spacing-js-value-${item}`)) return;
    const value = document.createElement('span');
    value.className = `spacing-js-value-${item}`;
    value.style.position = 'absolute';
    value.style.zIndex = `${zIndex}`;
    value.style.backgroundColor = targetColor;
    value.style.color = 'white';
    value.style.fontSize = '12px';
    value.style.lineHeight = '1';
    value.style.fontFamily = 'Helvetica, sans-serif';
    value.style.fontWeight = 'bold';
    value.style.borderRadius = '5px';
    value.style.padding = '2px 8px';
    value.style.textAlign = 'center';
    value.style.boxSizing = 'content-box';
    value.style.whiteSpace = 'nowrap';
    value.style.pointerEvents = 'none';
    value.style.display = 'none';
    SpacingMarker.appendToEl.appendChild(value);
  });
  // 辅助线
  directionArr.forEach((item: any) => {
    if (SpacingMarker.appendToEl.querySelector(`.spacing-js-subline-${item}`)) return;
    const subline = document.createElement('span');
    subline.className = `spacing-js-subline-${item}`;
    subline.style.position = 'absolute';
    subline.style.zIndex = `${zIndex - 2}`;
    subline.style.boxSizing = 'border-box';
    subline.style.pointerEvents = 'none';
    subline.style.display = 'none';
    SpacingMarker.appendToEl.appendChild(subline);
  });
}

export function cleanMarks(): void {
  SpacingMarker.appendToEl.querySelectorAll<HTMLElement>('*[class^="spacing-js-line"]').forEach((element) => {
    element.style.display = 'none';
  });
  SpacingMarker.appendToEl.querySelectorAll<HTMLElement>('*[class^="spacing-js-value"]').forEach((element) => {
    element.style.display = 'none';
  });
  SpacingMarker.appendToEl.querySelectorAll<HTMLElement>('*[class^="spacing-js-subline"]').forEach((element) => {
    element.style.display = 'none';
  });
}
